package com.naiterui.ehp.bs.recommend.service.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.naiterui.common.repository.page.PageVO;
import com.naiterui.ehp.bp.bo.patient.MsgMaPublishParamBO;
import com.naiterui.ehp.bp.bo.patient.RevisitDoctorBO;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.beans.BeanUtil;
import com.naiterui.ehp.bp.utils.biz.AppJumpProtocol;
import com.naiterui.ehp.bp.utils.biz.ScheduleUtils;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bp.utils.notice.AppNoticeUtil;
import com.naiterui.ehp.bp.utils.notice.AppPushUtil;
import com.naiterui.ehp.bs.recommend.bean.DrMedicationRecomInfo;
import com.naiterui.ehp.bs.recommend.bean.MedicationRecom;
import com.naiterui.ehp.bs.recommend.bean.MedicationRecomDetail;
import com.naiterui.ehp.bs.recommend.bean.mongo.AssistDrugRemind;
import com.naiterui.ehp.bs.recommend.bean.mongo.AssistDrugRemindItem;
import com.naiterui.ehp.bs.recommend.bean.mongo.AssistRevisit;
import com.naiterui.ehp.bs.recommend.bean.mongo.DrugRemindTrigger;
import com.naiterui.ehp.bs.recommend.exception.ExceptionCodes;
import com.naiterui.ehp.bs.recommend.remote.IPatientFeignClient;
import com.naiterui.ehp.bs.recommend.repository.mongo.IAssistDrugRemindRepository;
import com.naiterui.ehp.bs.recommend.repository.mongo.IAssistRevisitRepository;
import com.naiterui.ehp.bs.recommend.repository.mongo.IDrugRemindTriggerRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IMedicationRecomDetailRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IMedicationRecomInfoRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IMedicationRecomRepository;
import com.naiterui.ehp.bs.recommend.service.IAssistService;
import com.naiterui.ehp.bs.recommend.util.Constants;
import com.naiterui.ehp.bs.recommend.util.MedicationUtil;
import com.naiterui.ehp.bs.recommend.util.RecomBizUtil;
import com.naiterui.ehp.bs.recommend.vo.assist.DrRevisitVO;
import com.naiterui.ehp.bs.recommend.vo.assist.DrugRemindItemVO;
import com.naiterui.ehp.bs.recommend.vo.assist.DrugRemindParamVO;
import com.naiterui.ehp.bs.recommend.vo.assist.DrugRemindVO;
import com.naiterui.ehp.bs.recommend.vo.assist.OrderParamVO;
import com.naiterui.ehp.bs.recommend.vo.assist.PtRevisitDetailVO;
import com.naiterui.ehp.bs.recommend.vo.assist.PtRevisitVO;
import com.naiterui.ehp.bs.recommend.vo.prescription.PrescriptionItemVO;

import cn.hutool.core.collection.CollUtil;
import lombok.AllArgsConstructor;

/**
 * @author gaoliangliang
 * @date 2019-06-20 14:28
 * @since 1.0.0
 */
@Service
@AllArgsConstructor
public class AssistServiceImpl implements IAssistService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AssistServiceImpl.class);

    private final IMedicationRecomDetailRepository medicationRecomDetailRepository;
    private final IMedicationRecomRepository medicationRecomRepository;
    private final IMedicationRecomInfoRepository medicationRecomInfoRepository;
    private final IAssistRevisitRepository assistRevisitRepository;
    private final IAssistDrugRemindRepository assistDrugRemindRepository;
    private final IDrugRemindTriggerRepository drugRemindTriggerRepository;
    private final IPatientFeignClient patientFeignClient;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderComplete(OrderParamVO orderParamVO) {
        Set<Long> recomIdSet = StringUtil.convertLongStr2Set(orderParamVO.getRecomIds(), ",");
        int result = this.assistRevisitRepository.countByRecomIdIn(recomIdSet);
        if (result > 0) {
            LOGGER.info("order already callback");
            return;
        }
        List<MedicationRecom> recomList = this.medicationRecomRepository.findByIdIn(recomIdSet);
        List<MedicationRecomDetail> recomDetailList =
            this.medicationRecomDetailRepository.findByRecommendIdIn(recomIdSet);
        Map<Long, List<MedicationRecomDetail>> recomDetailMap = new HashMap<>();
        recomDetailList.forEach(recomDetail -> {
            List<MedicationRecomDetail> recomDetails =
                recomDetailMap.computeIfAbsent(recomDetail.getRecommendId(), o -> new ArrayList<>());
            recomDetails.add(recomDetail);
        });

        // List<DrMedicationRecomInfo> recomInfoList =
        // this.medicationRecomInfoRepository.findByRecommendIdIn(recomIdSet);
        // Map<Long, DrMedicationRecomInfo> recomInfoMap = CollectionUtils.isEmpty(recomInfoList) ? Maps.newHashMap() :
        // recomInfoList.stream()
        // .collect(
        // Collectors.toMap(
        // DrMedicationRecomInfo::getRecommendId,
        // o -> o));

        List<AssistRevisit> revisits = new ArrayList<>();
        List<AssistDrugRemind> drugReminds = new ArrayList<>();
        LOGGER.info("1.购药订单妥投触发系统用药提醒: {}", JsonMapper.toJson(recomList));
        recomList.forEach(recom -> {
            List<MedicationRecomDetail> details = recomDetailMap.getOrDefault(recom.getId(), Collections.emptyList());
            Optional<MedicationRecomDetail> maxRecomDetail = details.stream().max((r1, r2) -> RecomBizUtil
                .compareDrugCycle(r1.getDrugCycle(), r1.getDrugCycleUnit(), r2.getDrugCycle(), r2.getDrugCycleUnit()));
            LOGGER.info("2.购药订单妥投触发系统用药提醒: {}", JsonMapper.toJson(details));
            maxRecomDetail.ifPresent(detail -> {
                Double maxCycleDay = RecomBizUtil.getDrugCycle(detail.getDrugCycle(), detail.getDrugCycleUnit());
                // DrMedicationRecomInfo medicationRecomInfo = recomInfoMap.get(detail.getRecommendId());

                // 处理随访提醒
                if (Constants.VALID_MIN_DRUG_CYCLE.compareTo(maxCycleDay) < 0) {
                    revisits.add(AssistRevisit.builder().recomId(recom.getId()).createdAt(new Date())
                        .drugCycle(detail.getDrugCycle()).drugCycleUnit(detail.getDrugCycleUnit())
                        .dueAt(DateUtils.addHours(new Date(), (int)(maxCycleDay * 24))).startAt(new Date())
                        .doctorId(recom.getDoctorId()).patientId(recom.getPatientId()).build());
                }

                Optional<MedicationRecomDetail> maxFrequencyDetail = details.stream()
                    .max((r1, r2) -> RecomBizUtil.compareDrugFrequency(r1.getDosageCycle(), r1.getDosageCycleUnit(),
                        Integer.parseInt(r1.getDosageCount()), r2.getDosageCycle(), r2.getDosageCycleUnit(),
                        Integer.parseInt(r2.getDosageCount())));
                maxFrequencyDetail.ifPresent(maxCount -> {
                    // 处理用药提醒(用量周期，符合单：每【日】、每【小时】，才计算)
                    if (maxCount.getUsages().indexOf(",") < 0) {
                        LOGGER.info("不开启用药提醒: {}", JsonMapper.toJson(maxCount));
                        return;
                    }
                    String cycleUsage = maxCount.getUsages().substring(0, maxCount.getUsages().indexOf(","));
                    List<Integer> remindList = RecomBizUtil.getDrugRemind(cycleUsage);
                    LOGGER.info("2.购药订单妥投触发系统用药提醒: {}, cycleUsage: {}", JsonMapper.toJson(remindList), cycleUsage);
                    if (RecomBizUtil.canDrugRemind(cycleUsage) && CollectionUtils.isNotEmpty(remindList)) {
                        drugReminds.add(AssistDrugRemind.builder().patientId(recom.getPatientId())
                            .doctorId(recom.getDoctorId()).recomId(recom.getId())
                            .remindItems(remindList.stream()
                                .map(o -> AssistDrugRemindItem.builder().valid(true).hour(o).minute(0).build())
                                .collect(Collectors.toList()))
                            .dueAt(null).startAt(null).duration(maxCycleDay).createdAt(new Date()).valid(false)
                            .build());

                        // try {
                        // Map<String, Object> paramMap = new HashMap<>();
                        // paramMap.put("patientId", recom.getPatientId());
                        // paramMap.put("doctorId", recom.getDoctorId());
                        // paramMap.put("doctorName", medicationRecomInfo.getDoctorName());
                        // paramMap.put("recomId", recom.getId());
                        // this.patientFeignClient.patientPush(IPatientFeignClient.PATIENT_PUSH_PLATFORMID,
                        // IPatientFeignClient.PATIENT_PUSH_TEMPLATED_ALAEMCLOCK, JSON.toJSONString(paramMap));
                        // } catch (BusinessException e) {
                        // LOGGER.error("patient remindconfig push ERROR; ", e);
                        // }
                        // this.patientFeignClient.publishMaMessage(
                        // MsgMaPublishParamBO.builder().doctorId(recom.getDoctorId()).patientId(recom.getPatientId())
                        // .msgType(MsgMaPublishParamBO.MsgType.MEDICATION_REMINDER)
                        // .content(DateUtil.getCurrentCustomizeFormatDate("yyyy年MM月dd日 HH:mm")).build());
                    }
                });

            });
        });
        LOGGER.info("设置用药提醒集合：{}", JsonMapper.toJson(drugReminds));
        this.assistRevisitRepository.saveAll(revisits);
        this.assistDrugRemindRepository.saveAll(drugReminds);
    }

    @Override
    public PtRevisitVO ptRevisit(Long doctorId, Long patientId) throws BusinessException {
        Date nowZero = DateUtil.convertDate(new Date());
        Page<AssistRevisit> revisitPage = this.assistRevisitRepository.findByDoctorIdAndPatientIdAndDueAtBetween(
                doctorId,
                patientId,
                DateUtil.addDays(nowZero, ConfigUtil.getInt(Constants.REVISIT_REMIND_BEGIN_DAY)),
                DateUtil.addDays(nowZero, ConfigUtil.getInt(Constants.REVISIT_REMIND_END_DAY)), Pageable.unpaged());
        List<PtRevisitDetailVO> details = new ArrayList<>();
        Set<Long> recomIds = revisitPage.getContent().stream().map(AssistRevisit::getRecomId).collect(Collectors.toSet());
        List<MedicationRecom> recomLists = this.medicationRecomRepository.findByIdIn(recomIds);
        Map<Long, MedicationRecom> recomMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(recomLists)) {
            recomMap = recomLists.stream().collect(Collectors.toMap(MedicationRecom::getId, o -> o));
        }
        List<MedicationRecomDetail> recomDetailList = this.medicationRecomDetailRepository.findByRecommendIdIn(recomIds);
        Map<Long, List<MedicationRecomDetail>> recomDetailMap = new HashMap<>();
        recomDetailList.forEach(recomDetail -> {
            List<MedicationRecomDetail> recomDetails = recomDetailMap.computeIfAbsent(recomDetail.getRecommendId(), o -> new ArrayList<>());
            recomDetailMap.put(recomDetail.getRecommendId(), recomDetailList);
            recomDetails.add(recomDetail);
        });
        RevisitDoctorBO revisitDoctorBO = this.patientFeignClient.revisitDoctorBO(patientId, doctorId);
        Map<Long, MedicationRecom> finalRecomMap = recomMap;
        revisitPage.getContent().forEach(assistRevisit -> {
            MedicationRecom medicationRecom = finalRecomMap.get(assistRevisit.getRecomId());
            MedicationRecomDetail firstRecomDetail = recomDetailMap.get(assistRevisit.getRecomId()).get(0);
            details.add(PtRevisitDetailVO
                                .builder()
                                .diagnosis(medicationRecom.getDiagnosis())
                                .items(Collections.singletonList(new PrescriptionItemVO(firstRecomDetail.getPid(), firstRecomDetail.getSkuId(),
                                                                                        firstRecomDetail.getName(), firstRecomDetail
                                                                                                .getCommonName(), firstRecomDetail.getUsages(),
                                                                                        firstRecomDetail.getBakup(), firstRecomDetail.getQuantity())))
                                .overdueTime(assistRevisit.getDueAt())
                                .recomId(medicationRecom.getId())
                                .build());
        });
        return PtRevisitVO
                .builder()
                .doctorId(doctorId)
                .status(revisitDoctorBO.getStatus())
                .headUrl(revisitDoctorBO.getHeadUrl())
                .doctorName(revisitDoctorBO.getDoctorName())
                .department(revisitDoctorBO.getDepartment())
                .hospital(revisitDoctorBO.getHospital())
                .title(revisitDoctorBO.getTitle())
                .consultPrice(revisitDoctorBO.getConsultPrice())
                .details(details)
                .build();
    }


    @Override
    public PageVO<DrRevisitVO> drRevisit(Long doctorId, Pageable pageable) {
        Date nowZero = DateUtil.convertDate(new Date());
        Page<AssistRevisit> revisitPage = this.assistRevisitRepository.findByDoctorIdAndDueAtBetween(
                doctorId,
                nowZero,
                DateUtil.addDays(nowZero, ConfigUtil.getInt(Constants.REVISIT_REMIND_LIST_DAY)),
                pageable);
        List<DrRevisitVO> result = new ArrayList<>();
        Set<Long> recomIds = revisitPage.getContent().stream().map(AssistRevisit::getRecomId).collect(Collectors.toSet());
        List<MedicationRecom> recomLists = this.medicationRecomRepository.findByIdIn(recomIds);
        Map<Long, MedicationRecom> recomMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(recomLists)) {
            recomMap = recomLists.stream().collect(Collectors.toMap(MedicationRecom::getId, o -> o));
        }
        List<DrMedicationRecomInfo> recomInfoList = this.medicationRecomInfoRepository.findByRecommendIdIn(recomIds);
        Map<Long, DrMedicationRecomInfo> recomInfoMap = CollectionUtils.isEmpty(recomInfoList) ? Maps.newHashMap() : recomInfoList.stream()
                                                                                                                                  .collect(
                                                                                                                                          Collectors.toMap(
                                                                                                                                                  DrMedicationRecomInfo::getId,
                                                                                                                                                  o -> o));
        List<MedicationRecomDetail> recomDetailList = this.medicationRecomDetailRepository.findByRecommendIdIn(recomIds);
        Map<Long, List<MedicationRecomDetail>> recomDetailMap = new HashMap<>();
        recomDetailList.forEach(recomDetail -> {
            List<MedicationRecomDetail> recomDetails = recomDetailMap.computeIfAbsent(recomDetail.getRecommendId(), o -> new ArrayList<>());
            recomDetails.add(recomDetail);
        });
        Map<Long, MedicationRecom> finalRecomMap = recomMap;
        revisitPage.getContent().forEach(assistRevisit -> {
            MedicationRecom medicationRecom = finalRecomMap.get(assistRevisit.getRecomId());
            DrMedicationRecomInfo medicationRecomInfo = recomInfoMap.get(assistRevisit.getRecomId());
            MedicationRecomDetail firstRecomDetail = recomDetailMap.get(assistRevisit.getRecomId()).get(0);
            result.add(DrRevisitVO
                               .builder()
                               .beginDate(DateUtil.formatDate(new Date(), DateUtil.DATE_FORMAT))
                               .endDate(DateUtil.formatDate(assistRevisit.getDueAt(), DateUtil.DATE_FORMAT))
                               .flag(RecomBizUtil.dueToday(assistRevisit.getDueAt()))
                               .diagnosis(medicationRecom.getDiagnosis())
                               .drugCycle(new DecimalFormat("##.#").format(assistRevisit.getDrugCycle()))
                               .drugCycleUnit(assistRevisit.getDrugCycleUnit())
                               .patientId(medicationRecom.getPatientId())
                               .patientAge(medicationRecomInfo.getPatientAge())
                               .patientAgeUnit(medicationRecomInfo.getPatientAgeUnit())
                               .patientGender(medicationRecomInfo.getPatientGender())
                               .patientName(medicationRecomInfo.getPatientName())
                               .recomId(assistRevisit.getRecomId())
                               .items(Collections.singletonList(new PrescriptionItemVO(firstRecomDetail.getPid(), firstRecomDetail.getSkuId(),
                                                                                       firstRecomDetail.getName(), firstRecomDetail
                                                                                               .getCommonName(), firstRecomDetail.getUsages(),
                                                                                       firstRecomDetail.getBakup(), firstRecomDetail.getQuantity())))
                               .build());
        });
        return PageVO
                .newBuilder()
                .totalCount((int) revisitPage.getTotalElements())
                .pageSize(revisitPage.getPageable().getPageSize())
                .pageNo(revisitPage.getPageable().getPageNumber())
                .result(result)
                .build();
    }

    @Override
    public DrugRemindVO drugRemind(Long recomId) {
        AssistDrugRemind assistDrugRemind = this.assistDrugRemindRepository.findByRecomId(recomId);
        List<AssistDrugRemindItem> reminds = assistDrugRemind.getRemindItems();
        List<MedicationRecomDetail> recomDetails = this.medicationRecomDetailRepository.findByRecommendId(recomId);
        List<PrescriptionItemVO> items = new ArrayList<>();
        if (CollUtil.isNotEmpty(recomDetails)) {
            items = recomDetails.stream().map(recomDetail -> {
                PrescriptionItemVO prescriptionItemVO = new PrescriptionItemVO();
                BeanUtil.copyProperties(recomDetail, prescriptionItemVO);
                // 算出每日的频次
                prescriptionItemVO.setDailyFrequency(MedicationUtil.getAssistDailyFrequency(
                    recomDetail.getDosageCycle(), recomDetail.getDosageCycleUnit(), recomDetail.getDosageCount()));
                return prescriptionItemVO;
            }).sorted(Comparator.comparing(PrescriptionItemVO::getDailyFrequency).reversed())
                .collect(Collectors.toList());
        }
        return DrugRemindVO
                .builder()
                .recomdId(assistDrugRemind.getRecomId())
                .startAt(Optional.ofNullable(assistDrugRemind.getStartAt()).orElse(null))
                .valid(assistDrugRemind.getValid())
                .outDate(Optional.ofNullable(assistDrugRemind.getDueAt())
                                 .map(o -> DateUtil.compareDate(assistDrugRemind.getDueAt(), new Date()) <= 0)
                                 .orElse(false))
                .reminds(reminds.stream().map(remind -> DrugRemindItemVO
                        .builder()
                        .minite(remind.getMinute())
                        .hour(remind.getHour())
                        .valid(remind.getValid())
                        .build()).collect(Collectors.toList()))
            .items(items)
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveDrugRemind(DrugRemindParamVO drugRemindParamVO) throws BusinessException {
        AssistDrugRemind assistDrugRemind = this.assistDrugRemindRepository.findByRecomId(drugRemindParamVO.getRecomId());
        if (assistDrugRemind == null) {
            LOGGER.error(" drugRemind operate ERROR ; drugRemindNotExist : {}", drugRemindParamVO);
            return;
        }
        List<DrugRemindItemVO> remindsList = drugRemindParamVO.getRemindsList();
        if (CollUtil.isEmpty(remindsList)) {
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }
        LOGGER.debug(" drugRemind operate INFO : {}", drugRemindParamVO);
        switch (drugRemindParamVO.getOperate()) {
            case DrugRemindParamVO.DRUG_REMING_OPERATE_SAVE:
                remindsList.sort((o1, o2) -> {
                    int hourCompare = Integer.compare(o1.getHour(), o2.getHour());
                    int miniteCompare = Integer.compare(o1.getMinite(), o2.getMinite());
                    return hourCompare == 0 ? miniteCompare : hourCompare;
                });
                assistDrugRemind.setRemindItems(remindsList.stream().map(o -> AssistDrugRemindItem
                        .builder()
                        .minute(o.getMinite())
                        .hour(o.getHour())
                        .valid(o.getValid())
                        .build()).collect(Collectors.toList()));
                assistDrugRemind.setValid(true);
                if (assistDrugRemind.getStartAt() == null) {
                    assistDrugRemind.setStartAt(new Date());
                    assistDrugRemind.setDueAt(DateUtil.addHours(assistDrugRemind.getStartAt(), (int) (assistDrugRemind.getDuration() * 24)));
                    assistDrugRemind.setValid(true);
                    assistDrugRemind.setRemindItems(remindsList.stream().map(remindItem -> AssistDrugRemindItem
                            .builder()
                            .hour(remindItem.getHour())
                            .minute(remindItem.getMinite())
                            .valid(remindItem.getValid())
                            .build()).collect(Collectors.toList()));
                }
                try {
                    Map<String, Object> paramMap = new HashMap<>();
                    paramMap.put("message", "用药提醒已开启，系统会按时给您推送用药提醒，不再担心错过服药时间");
                    paramMap.put("patientId", assistDrugRemind.getPatientId());
                    paramMap.put("doctorId", assistDrugRemind.getDoctorId());
                    this.patientFeignClient.patientPush(IPatientFeignClient.PATIENT_PUSH_PLATFORMID,
                                                        IPatientFeignClient.PATIENT_PUSH_TEMPLATED_ALAEMCLOCK_CONFIG, JSON
                                                                .toJSONString(paramMap));
                } catch (BusinessException e) {
                    LOGGER.error("patient revisit push ERROR; ", e);
                }
                break;
            case DrugRemindParamVO.DRUG_REMING_OPERATE_CANCEL:
                assistDrugRemind.setValid(false);
                break;
            default:
                break;
        }
        this.assistDrugRemindRepository.update(assistDrugRemind);
        this.handlerTask(assistDrugRemind);
    }

    @Async
    @Override
    public void remindCallBack(Long recomId) throws BusinessException {
        DrugRemindTrigger trigger = this.drugRemindTriggerRepository.findFirstByRecomId(recomId);
        AssistDrugRemind assistDrugRemind = this.assistDrugRemindRepository.findByRecomId(recomId);
        if (trigger == null || assistDrugRemind == null || CollectionUtils.isEmpty(assistDrugRemind.getRemindItems())) {
            LOGGER.error("drug remind callback ERROR : remind not exist ; recomId={}", recomId);
            return;
        }
        Date fireTime = Optional.of(assistDrugRemind)
                                .map(AssistDrugRemind::getRemindItems)
                                .map(o -> {
                                    o.sort(AssistDrugRemindItem::compareTo);
                                    return o.stream().filter(AssistDrugRemindItem::getValid).findFirst().orElse(null);
                                })
                                .map(AssistDrugRemindItem::getDate)
                                .filter(result -> result.compareTo(assistDrugRemind.getDueAt()) <= 0)
                                .orElse(null);
        trigger.setNextRemindAt(fireTime);
        LOGGER.info("患者用药提醒回调时间: {}", JsonMapper.toJson(trigger));

        this.remindTask(trigger, assistDrugRemind);
        this.drugRemindTriggerRepository.update(trigger);
        this.patientFeignClient.publishMaMessage(MsgMaPublishParamBO.builder().doctorId(assistDrugRemind.getDoctorId())
            .patientId(assistDrugRemind.getPatientId()).msgType(MsgMaPublishParamBO.MsgType.MEDICATION_REMINDER)
            .path("pages/drugClock/index?recomId=" + recomId)
            .content(DateUtil.getCurrentCustomizeFormatDate("yyyy年MM月dd日 HH:mm")).build());
        // try {
        // List<MedicationRecomDetail> recomDetails =
        // this.medicationRecomDetailRepository.findByRecommendId(assistDrugRemind.getRecomId());
        //
        // Map<String, Object> paramMap = new HashMap<>();
        // String drugName =
        // recomDetails.stream().map(MedicationRecomDetail::getCommonName).collect(Collectors.joining(","));
        // paramMap.put("patientId", assistDrugRemind.getPatientId());
        // paramMap.put("doctorId", assistDrugRemind.getDoctorId());
        // paramMap.put("drugName",drugName);
        // paramMap.put("recomId", assistDrugRemind.getRecomId());
        // this.patientFeignClient.patientPush(IPatientFeignClient.PATIENT_PUSH_PLATFORMID,
        // IPatientFeignClient.PATIENT_PUSH_TEMPLATED_DRUGREMIND,
        // JSON.toJSONString(paramMap));
        // SMSUtil.Template template = SMSUtil.Template.MEDICATION_REMINDER_NOTICE_TEMPLATE;
        // PatientBaseBO patientBaseBO = patientFeignClient.getBaseInfoById(assistDrugRemind.getPatientId());
        // SMSUtil.sendSMS(patientBaseBO.getPhone(), template, patientBaseBO.getName(), drugName);
        //
        // } catch (BusinessException e) {
        // LOGGER.error("patient drug remind push ERROR; ", e);
        // }
    }

    @Async
    @Override
    public void revisitCallBack() {
        Date nowZero = DateUtil.convertDate(new Date());
        //医生当日
        List<AssistRevisit> drRevisits = this.assistRevisitRepository.findByDueAtBetween(nowZero, DateUtil.addDays(nowZero,
                                                                                                                   ConfigUtil.getInt(
                                                                                                                           Constants.REVISIT_REMIND_DAY)));
        Map<Long, Set<Long>> doctorCountMap = new HashMap<>();
        drRevisits.forEach(drRevisit -> {
            Set<Long> tempDoctorCount = doctorCountMap.computeIfAbsent(drRevisit.getDoctorId(), v -> new HashSet<>());
            tempDoctorCount.add(drRevisit.getPatientId());
        });
        doctorCountMap.forEach((doctorId, count) -> {
            try {
                AppNoticeUtil.sendSingleNotice(ConfigUtil.getString("ehp.domain.push"), doctorId, AppNoticeUtil.NoticeType.DR_REVISIT,
                                               new AppNoticeUtil.Revisit(count.size()));
                AppPushUtil.sendDrPush(ConfigUtil.getString("push.message.server"), doctorId, "您有" + count.size() + "位患者用药周期即将结束，点击查看详情",
                                       AppJumpProtocol.DR_RETURN_VISIT, count
                                               .toString());
            } catch (Exception e) {
                LOGGER.error("doctor revisit push ERROR; doctorId={}", doctorId);
            }
        });

        //患者明日结束用药提醒
        List<AssistRevisit> ptRevisits = this.assistRevisitRepository.findByDueAtBetween(
                DateUtil.addDays(nowZero, ConfigUtil.getInt(Constants.REVISIT_REMIND_BEGIN_DAY)),
                DateUtil.addDays(nowZero, ConfigUtil.getInt(Constants.REVISIT_REMIND_END_DAY)));
        Set<String> singSet = new HashSet<>();
        Set<Long> ptRecomIds = ptRevisits.stream().map(AssistRevisit::getRecomId).collect(Collectors.toSet());
        List<DrMedicationRecomInfo> recomInfoList = this.medicationRecomInfoRepository.findByRecommendIdIn(ptRecomIds);
        recomInfoList.forEach(recomInfo -> {
//            try {
                if (singSet.contains(recomInfo.getDoctorId() + "-" + recomInfo.getPatientId())) {
                    return;
                }
                singSet.add(recomInfo.getDoctorId() + "-" + recomInfo.getPatientId());
//                Map<String, Object> paramMap = new HashMap<>();
//                paramMap.put("patientId", recomInfo.getPatientId());
//                paramMap.put("doctorId", recomInfo.getDoctorId());
//                paramMap.put("doctorName", recomInfo.getDoctorName());
//                this.patientFeignClient.patientPush(IPatientFeignClient.PATIENT_PUSH_PLATFORMID, IPatientFeignClient.PATIENT_PUSH_TEMPLATED_REVISIT,
//                                                    JSON.toJSONString(paramMap));

                this.patientFeignClient.publishMaMessage(MsgMaPublishParamBO.builder()
                        .doctorId(recomInfo.getDoctorId())
                        .patientId(recomInfo.getPatientId())
                        .msgType(MsgMaPublishParamBO.MsgType.MEDICATION_REMINDER)
                .content(DateUtil.getCurrentCustomizeFormatDate("yyyy年MM月dd日 HH:mm"))
                        .build());
//            } catch (BusinessException e) {
//                LOGGER.error("patient revisit push ERROR; ", e);
//            }
        });
        LOGGER.debug("patient revisit push INFO; {}", singSet.toString());
    }

    @Override
    public Boolean getEnabledDrugremind(Long recomId) {
        List<MedicationRecomDetail> recomDetails = this.medicationRecomDetailRepository.findByRecommendId(recomId);
        if (CollUtil.isEmpty(recomDetails)) {
            return false;
        }
        return recomDetails.stream()
            .map(recomDetail -> MedicationUtil.getAssistDailyFrequency(recomDetail.getDosageCycle(),
                recomDetail.getDosageCycleUnit(), recomDetail.getDosageCount()))
            .anyMatch(r -> r > 0);
    }

    private void handlerTask(AssistDrugRemind assistDrugRemind) throws BusinessException {
        DrugRemindTrigger trigger = this.drugRemindTriggerRepository.findFirstByRecomId(assistDrugRemind.getRecomId());
        if (trigger == null) {
            trigger = DrugRemindTrigger
                    .builder()
                    .recomId(assistDrugRemind.getRecomId())
                    .doctorId(assistDrugRemind.getDoctorId())
                    .patientId(assistDrugRemind.getPatientId())
                    .build();
            this.drugRemindTriggerRepository.save(trigger);
        }
        LOGGER.info("处理用药提醒任务：{}", JsonMapper.toJson(trigger));
        if (CollectionUtils.isEmpty(assistDrugRemind.getRemindItems())) {
            return;
        }
        assistDrugRemind.getRemindItems().sort(AssistDrugRemindItem::compareTo);
        Optional<AssistDrugRemindItem> drugRemindItem = assistDrugRemind.getRemindItems().stream().filter(AssistDrugRemindItem::getValid).findFirst();
        trigger.setNextRemindAt(drugRemindItem
                                        .map(AssistDrugRemindItem::getDate)
                                        .filter(result -> result.compareTo(assistDrugRemind.getDueAt()) <= 0)
                                        .orElse(null));

        this.remindTask(trigger, assistDrugRemind);

        this.drugRemindTriggerRepository.update(trigger);
    }

    private void remindTask(DrugRemindTrigger trigger, AssistDrugRemind assistDrugRemind) throws BusinessException {
        ScheduleUtils.removeCustomerTask(ConfigUtil.getString(Constants.TASK_SCHEDULE_HOST),
            ScheduleUtils.TASK_TYPE_DRUG_REMIND, assistDrugRemind.getRecomId().toString());
        if (assistDrugRemind.getValid() && trigger.getNextRemindAt() != null) {
            LOGGER.info("设置下次用药提醒,trigger: {}, assistDrugRemind: {}", JsonMapper.toJson(trigger),
                JsonMapper.toJson(assistDrugRemind));
            Map<String, String> param = new HashMap<>();
            param.put("recomId", trigger.getRecomId().toString());
            ScheduleUtils.addCustomerTask(
                    ConfigUtil.getString(Constants.TASK_SCHEDULE_HOST),
                    DateUtil.formatDate(trigger.getNextRemindAt(), DateUtil.CRON_TIME_FORMAT),
                    ScheduleUtils.TASK_TYPE_DRUG_REMIND,
                    assistDrugRemind.getRecomId().toString(),
                    ConfigUtil.getString(Constants.RECOM_DRUG_REMIND_CALLBACK), param);
        }
    }
}
